home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / imap / ANSI / c-client / env_unix.c < prev    next >
C/C++ Source or Header  |  1997-02-21  |  16KB  |  518 lines

  1. /*
  2.  * Program:    UNIX environment routines
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    1 August 1988
  13.  * Last Edited:    21 February 1997
  14.  *
  15.  * Copyright 1995 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made available
  24.  * "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36. /* c-client environment parameters */
  37.  
  38. static char *myUserName = NIL;    /* user name */
  39. static char *myHomeDir = NIL;    /* home directory name */
  40. static char *myLocalHost = NIL;    /* local host name */
  41. static char *myNewsrc = NIL;    /* newsrc file name */
  42. static char *sysInbox = NIL;    /* system inbox name */
  43. static char *newsActive = NIL;    /* news active file */
  44. static char *newsSpool = NIL;    /* news spool */
  45. static char *blackBoxDir = NIL;    /* black box directory name */
  46. static int blackBox = NIL;    /* is a black box */
  47. static long mbx_protection = 0600;
  48. static long sub_protection = 0600;
  49. static long lock_protection = 0666;
  50. static long disableFcntlLock =    /* flock() emulator is a no-op */
  51. #ifdef SVR4_DISABLE_FLOCK
  52.   T
  53. #else
  54.   NIL
  55. #endif
  56.   ;
  57. static long lockEaccesError =    /* warning on EACCES errors on .lock files */
  58. #ifdef WARN_LOCK_EACCES_ERRORS
  59.   T
  60. #else
  61.   NIL
  62. #endif
  63.   ;
  64. static MAILSTREAM *defaultProto = NIL;
  65. static char *userFlags[NUSERFLAGS] = {NIL};
  66.  
  67. #include "write.c"        /* include safe writing routines */
  68. #include "writev.c"        /* include safe writing routines */
  69.  
  70. /* Environment manipulate parameters
  71.  * Accepts: function code
  72.  *        function-dependent value
  73.  * Returns: function-dependent return value
  74.  */
  75.  
  76. void *env_parameters (long function,void *value)
  77. {
  78.   switch ((int) function) {
  79.   case SET_USERNAME:
  80.     if (myUserName) fs_give ((void **) &myUserName);
  81.     myUserName = cpystr ((char *) value);
  82.     break;
  83.   case GET_USERNAME:
  84.     value = (void *) myUserName;
  85.     break;
  86.   case SET_HOMEDIR:
  87.     if (myHomeDir) fs_give ((void **) &myHomeDir);
  88.     myHomeDir = cpystr ((char *) value);
  89.     break;
  90.   case GET_HOMEDIR:
  91.     value = (void *) myHomeDir;
  92.     break;
  93.   case SET_LOCALHOST:
  94.     if (myLocalHost) fs_give ((void **) &myLocalHost);
  95.     myLocalHost = cpystr ((char *) value);
  96.     break;
  97.   case GET_LOCALHOST:
  98.     value = (void *) myLocalHost;
  99.     break;
  100.   case SET_NEWSRC:
  101.     if (myNewsrc) fs_give ((void **) &myNewsrc);
  102.     myNewsrc = cpystr ((char *) value);
  103.     break;
  104.   case GET_NEWSRC:
  105.     value = (void *) myNewsrc;
  106.     break;
  107.   case SET_NEWSACTIVE:
  108.     if (newsActive) fs_give ((void **) &newsActive);
  109.     newsActive = cpystr ((char *) value);
  110.     break;
  111.   case GET_NEWSACTIVE:
  112.     value = (void *) newsActive;
  113.     break;
  114.   case SET_NEWSSPOOL:
  115.     if (newsSpool) fs_give ((void **) &newsSpool);
  116.     newsSpool = cpystr ((char *) value);
  117.     break;
  118.   case GET_NEWSSPOOL:
  119.     value = (void *) newsSpool;
  120.     break;
  121.   case SET_SYSINBOX:
  122.     if (sysInbox) fs_give ((void **) &sysInbox);
  123.     sysInbox = cpystr ((char *) value);
  124.     break;
  125.   case GET_SYSINBOX:
  126.     value = (void *) sysInbox;
  127.     break;
  128.  
  129.   case SET_MBXPROTECTION:
  130.     mbx_protection = (long) value;
  131.     break;
  132.   case GET_MBXPROTECTION:
  133.     value = (void *) mbx_protection;
  134.     break;
  135.   case SET_SUBPROTECTION:
  136.     sub_protection = (long) value;
  137.     break;
  138.   case GET_SUBPROTECTION:
  139.     value = (void *) sub_protection;
  140.     break;
  141.   case SET_LOCKPROTECTION:
  142.     lock_protection = (long) value;
  143.     break;
  144.   case GET_LOCKPROTECTION:
  145.     value = (void *) lock_protection;
  146.     break;
  147.   case SET_DISABLEFCNTLLOCK:
  148.     disableFcntlLock = (long) value;
  149.     break;
  150.   case GET_DISABLEFCNTLLOCK:
  151.     value = (void *) disableFcntlLock;
  152.     break;
  153.   case SET_LOCKEACCESERROR:
  154.     lockEaccesError = (long) value;
  155.     break;
  156.   case GET_LOCKEACCESERROR:
  157.     value = (void *) lockEaccesError;
  158.     break;
  159.   default:
  160.     value = NIL;        /* error case */
  161.     break;
  162.   }
  163.   return value;
  164. }
  165.  
  166. /* Write current time
  167.  * Accepts: destination string
  168.  *        optional format of day-of-week prefix
  169.  *        format of date and time
  170.  *        flag whether to append symbolic timezone
  171.  */
  172.  
  173. static void do_date (char *date,char *prefix,char *fmt,int suffix)
  174. {
  175.   time_t tn = time (0);
  176.   struct tm *t = gmtime (&tn);
  177.   int zone = t->tm_hour * 60 + t->tm_min;
  178.   int julian = t->tm_yday;
  179.   t = localtime (&tn);        /* get local time now */
  180.                 /* minus UTC minutes since midnight */
  181.   zone = t->tm_hour * 60 + t->tm_min - zone;
  182.   /* julian can be one of:
  183.    *  36x  local time is December 31, UTC is January 1, offset -24 hours
  184.    *    1  local time is 1 day ahead of UTC, offset +24 hours
  185.    *    0  local time is same day as UTC, no offset
  186.    *   -1  local time is 1 day behind UTC, offset -24 hours
  187.    * -36x  local time is January 1, UTC is December 31, offset +24 hours
  188.    */
  189.   if (julian = t->tm_yday -julian)
  190.     zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
  191.   if (prefix) {            /* want day of week? */
  192.     sprintf (date,prefix,days[t->tm_wday]);
  193.     date += strlen (date);    /* make next sprintf append */
  194.   }
  195.                 /* output the date */
  196.   sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  197.        t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
  198.                 /* append timezone suffix if desired */
  199.   if (suffix) rfc822_timezone (date,(void *) t);
  200. }
  201.  
  202.  
  203. /* Write current time in RFC 822 format
  204.  * Accepts: destination string
  205.  */
  206.  
  207. void rfc822_date (char *date)
  208. {
  209.   do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",T);
  210. }
  211.  
  212.  
  213. /* Write current time in internal format
  214.  * Accepts: destination string
  215.  */
  216.  
  217. void internal_date (char *date)
  218. {
  219.   do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
  220. }
  221.  
  222. /* Initialize environment
  223.  * Accepts: user name
  224.  *        home directory name
  225.  * Returns: T, always
  226.  */
  227.  
  228. long env_init (char *user,char *home)
  229. {
  230.   extern MAILSTREAM STDPROTO;
  231.   struct stat sbuf;
  232.   char tmp[MAILTMPLEN];
  233.   struct hostent *host_name;
  234.   if (myUserName) fatal ("env_init called twice!");
  235.   myUserName = cpystr (user);    /* remember user name */
  236.   myHomeDir = cpystr (home);    /* and home directory */
  237.   sprintf (tmp,"%s/%s",MAILSPOOL,myUserName);
  238.   sysInbox = cpystr (tmp);    /* system inbox is from mail spool */
  239.   dorc ("/etc/imapd.conf");    /* do systemwide */
  240.   if (blackBoxDir) {        /* build black box directory name */
  241.     sprintf (tmp,"%s/%s",blackBoxDir,myUserName);
  242.                 /* if black box if exists and directory */
  243.     if (blackBox = (!stat (tmp,&sbuf)) && (sbuf.st_mode & S_IFDIR)) {
  244.                 /* flush standard values */
  245.       fs_give ((void **) &myHomeDir);
  246.       fs_give ((void **) &sysInbox);
  247.       myHomeDir = cpystr (tmp);    /* set black box values in their place */
  248.       sysInbox = cpystr (strcat (tmp,"/INBOX"));
  249.     }
  250.   }
  251.   else blackBoxDir = "";    /* make sure user rc files don't try this */
  252.                 /* do user rc files */
  253.   dorc (strcat (strcpy (tmp,myhomedir ()),"/.mminit"));
  254.   dorc (strcat (strcpy (tmp,myhomedir ()),"/.imaprc"));
  255.   if (!myLocalHost) {        /* have local host yet? */
  256.     gethostname(tmp,MAILTMPLEN);/* get local host name */
  257.     myLocalHost = cpystr ((host_name = gethostbyname (tmp)) ?
  258.               host_name->h_name : tmp);
  259.   }
  260.   if (!myNewsrc) {        /* set news file name if not defined */
  261.     sprintf (tmp,"%s/.newsrc",myhomedir ());
  262.     myNewsrc = cpystr (tmp);
  263.   }
  264.   if (!newsActive) newsActive = cpystr (ACTIVEFILE);
  265.   if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
  266.                 /* force default prototype to be set */
  267.   if (!defaultProto) defaultProto = &STDPROTO;
  268.                 /* re-do open action to get flags */
  269.   (*defaultProto->dtb->open) (NIL);
  270.   return T;
  271. }
  272.  
  273. /* Return my user name
  274.  * Returns: my user name
  275.  */
  276.  
  277. char *myusername ()
  278. {
  279.   if (!myUserName) {        /* get user name if don't have it yet */
  280.     char *name = (char *) getlogin ();
  281.     char *dir = getenv ("HOME");
  282.     struct passwd *pw;
  283.     if (((name && *name) && (pw = getpwnam (name)) &&
  284.      (pw->pw_uid == geteuid ())) || (pw = getpwuid (geteuid ())))
  285.       env_init (pw->pw_name,(dir && *dir) ? dir : pw->pw_dir);
  286.     else fatal ("Unable to look up user in passwd file");
  287.   }
  288.   return myUserName;
  289. }
  290.  
  291.  
  292. /* Return my local host name
  293.  * Returns: my local host name
  294.  */
  295.  
  296. char *mylocalhost ()
  297. {
  298.   if (!myLocalHost) myusername ();
  299.   return myLocalHost;
  300. }
  301.  
  302.  
  303. /* Return my home directory name
  304.  * Returns: my home directory name
  305.  */
  306.  
  307. char *myhomedir ()
  308. {
  309.   if (!myHomeDir) myusername ();/* initialize if first time */
  310.   return myHomeDir;
  311. }
  312.  
  313.  
  314. /* Return system standard INBOX
  315.  * Accepts: buffer string
  316.  */
  317.  
  318. char *sysinbox ()
  319. {
  320.   if (!sysInbox) myusername ();    /* call myusername() if first time */
  321.   return sysInbox;
  322. }
  323.  
  324. /* Return mailbox file name
  325.  * Accepts: destination buffer
  326.  *        mailbox name
  327.  * Returns: file name or NIL if error
  328.  */
  329.  
  330. char *mailboxfile (char *dst,char *name)
  331. {
  332.   struct passwd *pw;
  333.   char *s,*t,tmp[MAILTMPLEN];
  334.   char *dir = myhomedir ();
  335.   *dst = '\0';            /* erase buffer */
  336.   if (blackBox && strstr (name,"/..")) dst = NIL;
  337.   else switch (*name) {        /* dispatch based on first character */
  338.   case '*':            /* bboard? */
  339.     if ((pw = getpwnam ("ftp")) && pw->pw_dir && !strstr (name,"..") &&
  340.     !strstr (name,"//") && !strstr (name,"/~")) {
  341.       sprintf (dst,"%s/%s",pw->pw_dir,name + 1);
  342.       break;
  343.     }
  344.                 /* drops in */
  345.   case '#':            /* namespace name? */
  346.     dst = NIL;            /* definite error */
  347.     break;            /* can't be used */
  348.   default:            /* any other name, ignore extraneous context */
  349.     if ((s = strstr (name,"/~")) || (s = strstr (name,"//"))) name = s + 1;
  350.     switch (*name) {        /* dispatch based on first character */
  351.     case '/':            /* absolute file path */
  352.       if (blackBox && strncmp (name,sysInbox,strlen (myHomeDir)+1)) dst = NIL;
  353.       else strcpy (dst,name);
  354.       break;
  355.     case '.':            /* these names may be private */
  356.       if (blackBox && (name[1] == '.')) dst = NIL;
  357.       else sprintf (dst,"%s/%s",dir,name);
  358.       break;
  359.     case '~':            /* home directory */
  360.       if (blackBox) dst = NIL;    /* don't permit this for now */
  361.       else {
  362.     if (name[1] != '/') {    /* if not want my own home directory */
  363.       strcpy (tmp,name + 1);/* copy user name */
  364.       if (name = strchr (tmp,'/')) *name++ = '\0';
  365.       else name = "";    /* prevent code before from being surprised */
  366.                 /* look it up in password file */
  367.       if (!(dir = ((pw = getpwnam (tmp)) ? pw->pw_dir : NIL))) break;
  368.     }
  369.     else name += 2;        /* skip past user name */
  370.     sprintf (dst,"%s/%s",dir,name);
  371.       }
  372.       break;
  373.     default:            /* some other name */
  374.                 /* non-INBOX name is in home directory */
  375.       if (strcmp (ucase (strcpy (tmp,name)),"INBOX"))
  376.     sprintf (dst,"%s/%s",dir,name);
  377.                 /* blackbox INBOX is always in home dir */
  378.       else if (blackBox) sprintf (dst,"%s/INBOX",dir);
  379.                 /* empty name means driver selects INBOX */
  380.       break;
  381.     }
  382.   }
  383.   return dst;
  384. }
  385.  
  386. /* Build status lock file name
  387.  * Accepts: scratch buffer
  388.  *        file name
  389.  * Returns: name of file to lock or NIL if error
  390.  */
  391.  
  392. char *lockname (char *tmp,char *fname)
  393. {
  394.   char *s = strrchr (fname,'/');
  395.   struct stat sbuf;
  396.   if (stat (fname,&sbuf))    /* get file status */
  397.     sprintf (tmp,"/tmp/.%s",s ? s : fname);
  398.   else sprintf (tmp,"/tmp/.%hx.%lx",sbuf.st_dev,sbuf.st_ino);
  399.   return chk_notsymlink (tmp,T) ? tmp : NIL;
  400. }
  401.  
  402.  
  403. /* Check to make sure not a symlink
  404.  * Accepts: file name
  405.  *        check hard link flag
  406.  * Returns: T if not symlink, NIL if symlink
  407.  */
  408.  
  409. long chk_notsymlink (char *name,long chkhard)
  410. {
  411.   struct stat sbuf;
  412.                 /* OK if not exists */
  413.   if (lstat (name,&sbuf)) return T;
  414.   if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
  415.     mm_log ("SECURITY ALERT: symbolic link on lock name!",ERROR);
  416.     syslog (LOG_CRIT,"SECURITY PROBLEM: lock file %s is a symbolic link",name);
  417.     return NIL;
  418.   }
  419.   if (chkhard && (sbuf.st_nlink > 1)) {
  420.     mm_log ("SECURITY ALERT: hard link to lock name!",ERROR);
  421.     syslog (LOG_CRIT,"SECURITY PROBLEM: lock file %s has a hard link",name);
  422.     return NIL;
  423.   }
  424.   return T;            /* OK */
  425. }
  426.  
  427. /* Determine default prototype stream to user
  428.  * Returns: default prototype stream
  429.  */
  430.  
  431. MAILSTREAM *default_proto ()
  432. {
  433.   myusername ();        /* make sure initialized */
  434.   return defaultProto;        /* return default driver's prototype */
  435. }
  436.  
  437.  
  438. /* Set up user flags for stream
  439.  * Accepts: MAIL stream
  440.  * Returns: MAIL stream with user flags set up
  441.  */
  442.  
  443. MAILSTREAM *user_flags (MAILSTREAM *stream)
  444. {
  445.   int i;
  446.   myusername ();        /* make sure initialized */
  447.   for (i = 0; i < NUSERFLAGS; ++i) stream->user_flags[i] = userFlags[i];
  448.   return stream;
  449. }
  450.  
  451. /* Process rc file
  452.  * Accepts: file name
  453.  */
  454.  
  455. void dorc (char *file)
  456. {
  457.   int i;
  458.   char *s,*t,*k,tmp[MAILTMPLEN],tmpx[MAILTMPLEN];
  459.   extern MAILSTREAM STDPROTO;
  460.   DRIVER *d;
  461.   FILE *f = fopen (file,"r");
  462.   if (!f) return;        /* punt if no file */
  463.   while ((s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))) {
  464.     *t++ = '\0';        /* tie off line, find second space */
  465.     if ((k = strchr (s,' ')) && (k = strchr (++k,' '))) {
  466.       *k++ = '\0';        /* tie off two words*/
  467.       lcase (s);        /* make case-independent */
  468.       if (!(defaultProto || strcmp (s,"set empty-folder-format"))) {
  469.     if (!strcmp (lcase (k),"same-as-inbox"))
  470.       defaultProto = ((d = mail_valid (NIL,"INBOX",NIL)) &&
  471.               strcmp (d->name,"dummy")) ?
  472.                 ((*d->open) (NIL)) : &STDPROTO;
  473.     else if (!strcmp (k,"system-standard")) defaultProto = &STDPROTO;
  474.     else {            /* see if a driver name */
  475.       for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
  476.            d && strcmp (d->name,k); d = d->next);
  477.       if (d) defaultProto = (*d->open) (NIL);
  478.       else {        /* duh... */
  479.         sprintf (tmpx,"Unknown empty folder format in %s: %s",file,k);
  480.         mm_log (tmpx,WARN);
  481.       }
  482.     }
  483.       }
  484.       else if (!(userFlags[0] || strcmp (s,"set keywords"))) {
  485.     k = strtok (k,", ");    /* yes, get first keyword */
  486.                 /* copy keyword list */
  487.     for (i = 0; k && i < NUSERFLAGS; ++i) {
  488.       if (userFlags[i]) fs_give ((void **) &userFlags[i]);
  489.       userFlags[i] = cpystr (k);
  490.       k = strtok (NIL,", ");
  491.     }
  492.       }
  493.       else if (!strcmp (s,"set from-widget"))
  494.     mail_parameters (NIL,SET_FROMWIDGET,strcmp (lcase (k),"header-only") ?
  495.              (void *) T : NIL);
  496.       else if (!strcmp (s,"set black-box-directory")) {
  497.     if (blackBoxDir)    /* users aren't allowed to do this */
  498.       mm_log ("Can't set black-box-directory in user init",ERROR);
  499.     else blackBoxDir = cpystr (k);
  500.       }
  501.       else if (!strcmp (s,"set local-host")) {
  502.     fs_give ((void **) &myLocalHost);
  503.     myLocalHost = cpystr (k);
  504.       }
  505.       else if (!strcmp (s,"set news-active-file")) {
  506.     fs_give ((void **) &newsActive);
  507.     newsActive = cpystr (k);
  508.       }
  509.       else if (!strcmp (s,"set news-spool-directory")) {
  510.     fs_give ((void **) &newsSpool);
  511.     newsSpool = cpystr (k);
  512.       }
  513.     }
  514.     s = t;            /* try next line */
  515.   }
  516.   fclose (f);            /* flush the file */
  517. }
  518.